#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include "platforms/i2c.h"
#include "retval.h"

typedef struct {
	char dev_name[32];
	int fd;
	bool inited;
} i2c_ctxt_t;

i2c_t i2c_init()
{
	int fd = 0;              /* file descriptor */
	i2c_ctxt_t* ctxt = NULL; /* i2c context */

	/* 打开 i2c 设备节点 */
	fd = open("/dev/i2c-0", O_RDWR);
	if (fd < 0) {
		printf("err: open(%s, O_RDWR), ret = %d\n", "/dev/i2c-0", fd);
		return NULL;
	}

	/* 创建 i2c 对象 */
	ctxt = malloc(sizeof(i2c_ctxt_t));
	ctxt->fd = fd;
	ctxt->inited = true;

	return (i2c_t)ctxt;
}

int i2c_write(i2c_t i2c, uint8_t slave, uint8_t* msg, uint32_t len)
{
	int rc = 0;
	int fd = 0;
	i2c_ctxt_t* ctxt = NULL;

	/* 参数有效性校验 */
	if (NULL == i2c) {
		printf("inval: i2c\n");
		return -EINVAL;
	}

	if (NULL == msg) {
		printf("inval: msg\n");
		return -EINVAL;
	}

	ctxt = (i2c_ctxt_t*)i2c;
	if (true != ctxt->inited) {
		printf("err: i2c not inited\n");
		return -ENOTINIT;
	}

	/* 设置 i2c 从设备的地址 */
	fd = ctxt->fd;
	rc = ioctl(fd, I2C_SLAVE, slave);
	if (rc) {
		printf("err: ioctl(%d, I2C_SLAVE, 0x%02x), ret = %d\n", fd, slave, rc);
		return EIO;
	}

	/* 写入数据到 i2c 从设备 */
	rc = write(fd, msg, len);
	if (rc != len) {
		printf("err: write(%d, msg, %d), ret = %d\n", fd, len, rc);
		return -EWRITE;
	}

	return 0;
}

int i2c_read(i2c_t i2c, uint8_t slave, uint8_t* msg, uint32_t len)
{
	int rc = 0;
	int fd = 0;
	i2c_ctxt_t* ctxt = NULL;

	/* 参数有效性校验 */
	if (NULL == i2c) {
		printf("inval: i2c\n");
		return -EINVAL;
	}

	if (NULL == msg) {
		printf("inval: msg\n");
		return -EINVAL;
	}

	ctxt = (i2c_ctxt_t*)i2c;
	if (true != ctxt->inited) {
		printf("err: i2c not inited\n");
		return -ENOTINIT;
	}

	/* 设置 i2c 从设备的地址 */
	fd = ctxt->fd;
	rc = ioctl(fd, I2C_SLAVE, slave);
	if (rc) {
		printf("err: ioctl(%d, I2C_SLAVE, 0x%02x), ret = %d\n", fd, slave, rc);
		return EIO;
	}

	/* 从 i2c 从设备中读取数据 */
	rc = read(fd, msg, len);
	if (rc != len) {
		printf("err: read(%d, msg, %d), ret = %d\n", fd, len, rc);
		return -EREAD;
	}

	return 0;
}

void i2c_deinit(i2c_t i2c)
{
	int fd = 0;
	i2c_ctxt_t* ctxt = NULL;

	/* 参数有效性校验 */
	if (NULL == i2c) {
		printf("inval: i2c\n");
		return;
	}

	ctxt = (i2c_ctxt_t*)i2c;
	if (true != ctxt->inited) {
		printf("err: i2c not inited\n");
		return;
	}

	/* 关闭 SPI 设备节点 */
	fd = ctxt->fd;
	close(fd);
	free(ctxt);
	ctxt = NULL;

	ctxt->inited = false;
}
